const { context, getOctokit } = require('@actions/github')

const token = process.env.GITHUB_TOKEN
const octokit = getOctokit(token)

async function run() {
    try {
        const pr = context.payload.pull_request
        const { owner, repo } = context.repo
        const prNumber = pr.number

        console.log(`Working with repository: ${owner}/${repo}`)
        console.log(`PR number: ${prNumber}`)
        console.log(`PR author: ${pr.user.login}`)
        console.log(`Head repo: ${pr.head.repo.full_name}`)
        console.log(`Base repo: ${pr.base.repo.full_name}`)
        console.log(`Head SHA: ${pr.head.sha}`)
        console.log(`Base SHA: ${pr.base.sha}`)
        console.log(`Head ref: ${pr.head.ref}`)
        console.log(`Base ref: ${pr.base.ref}`)

        const filesChanged = await octokit.rest.pulls.listFiles({
            owner,
            repo,
            pull_number: prNumber,
        })

        const comments = []

        // Check 1: New resource links in /resources folder
        const resourceFiles = filesChanged.data.filter(
            (file) => file.filename.startsWith('resources/') && file.filename.endsWith('.ts'),
        )

        if (resourceFiles.length > 0) {
            console.log(`Found ${resourceFiles.length} modified resource file(s). Checking for new resource links...`)
            const newLinks = await checkForNewResourceLinks(owner, repo, pr, resourceFiles)
            if (newLinks.length > 0) {
                const linkComment =
                    newLinks.length === 1
                        ? `**New resource link:** ${newLinks[0]}`
                        : ['**New resource links:**', '', ...newLinks.map((link) => `- ${link}`)].join('\n')
                comments.push(linkComment)
            }
        }

        // Check 2: Edits to README.md or /db folder
        const autoGeneratedFiles = filesChanged.data.filter(
            (file) => file.filename.toLowerCase() === 'readme.md' || file.filename.startsWith('db/'),
        )

        if (autoGeneratedFiles.length > 0) {
            console.log(`Auto-generated file modifications detected in ${autoGeneratedFiles.length} file(s)`)
            const autoGenWarning =
                'Thanks for your contribution!\n❗️ **Warning:** The `README.md` file and the `/db` folder are auto-generated, so please do not edit them. Changes related to resources should happen within the `/resources` folder. Read the [contribution guidelines](https://github.com/marcelscruz/dev-resources/blob/main/CONTRIBUTING.md) for more details.'
            comments.push(autoGenWarning)
        }

        // Post all comments as a single comment
        if (comments.length > 0) {
            const finalComment = comments.join('\n\n---\n\n')

            await octokit.rest.issues.createComment({
                owner,
                repo,
                issue_number: prNumber,
                body: finalComment,
            })

            console.log('Comment posted with all checks.')
        } else {
            console.log('No issues found in this PR.')
        }
    } catch (error) {
        console.error('Error in PR review automation:', error)
        // Don't exit with error code to avoid failing the entire workflow
        // Just log the error and continue
    }
}

async function checkForNewResourceLinks(owner, repo, pr, resourceFiles) {
    try {
        const newLinks = []

        for (const file of resourceFiles) {
            console.log(`Checking file: ${file.filename}`)

            let baseContent = ''
            let headContent = ''

            // Get base content (if file exists in base)
            try {
                const baseRes = await octokit.rest.repos.getContent({
                    owner,
                    repo,
                    path: file.filename,
                    ref: pr.base.sha,
                })
                baseContent = Buffer.from(baseRes.data.content, 'base64').toString('utf8')
            } catch (error) {
                // File doesn't exist in base (new file)
                console.log(`File ${file.filename} is new in this PR`)
            }

            // Get head content
            try {
                const headRes = await octokit.rest.repos.getContent({
                    owner: pr.head.repo.owner.login,
                    repo: pr.head.repo.name,
                    path: file.filename,
                    ref: pr.head.sha,
                })
                headContent = Buffer.from(headRes.data.content, 'base64').toString('utf8')
            } catch (error) {
                console.log(`Could not get head content for ${file.filename}:`, error.message)
                continue
            }

            // Extract URLs from TypeScript resource files
            const baseUrls = new Set(extractUrlsFromTypeScript(baseContent))
            const headUrls = new Set(extractUrlsFromTypeScript(headContent))

            const fileNewLinks = [...headUrls].filter((url) => !baseUrls.has(url))
            newLinks.push(...fileNewLinks)

            console.log(
                `File ${file.filename}: Base URLs: ${baseUrls.size}, Head URLs: ${headUrls.size}, New: ${fileNewLinks.length}`,
            )
        }

        console.log(`Total new resource links found: ${newLinks.length}`)
        if (newLinks.length > 0) {
            console.log('New links:', newLinks)
        }

        return newLinks
    } catch (error) {
        console.error('Error checking for new resource links:', error)
        return [] // Return empty array on error to avoid breaking the workflow
    }
}

function extractUrlsFromTypeScript(content) {
    const urls = []

    // Match url property in TypeScript objects: url: 'https://...' or url: "https://..."
    const urlMatches = content.matchAll(/url:\s*['"`]([^'"`]+)['"`]/g)

    for (const match of urlMatches) {
        const url = match[1]
        // Only include http/https URLs
        if (url.startsWith('http://') || url.startsWith('https://')) {
            urls.push(url)
        }
    }

    return urls
}

run().catch((error) => {
    console.error(error)
    process.exit(1)
})
